{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "8bbf6ba4",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 基于 Function Calling 的实现\n",
    "\n",
    "LOGISTICS_TOOLS = [\n",
    "    {\n",
    "        \"type\": \"function\",\n",
    "        \"function\": {\n",
    "            \"name\": \"query_logistics_companies\",\n",
    "            \"description\": \"查询支持的物流公司信息\"\n",
    "        }\n",
    "    },\n",
    "    {\n",
    "        \"type\": \"function\",\n",
    "        \"function\": {\n",
    "            \"name\": \"calculate_shipping_fee\",\n",
    "            \"description\": \"计算运费\",\n",
    "            \"parameters\": {\n",
    "                \"type\": \"object\",\n",
    "                \"properties\": {\n",
    "                    \"weight\": {\"type\": \"number\", \"description\": \"重量(kg)\"},\n",
    "                    \"distance\": {\"type\": \"number\", \"description\": \"距离(km)\"},\n",
    "                    \"company\": {\"type\": \"string\", \"description\": \"物流公司\"}\n",
    "                },\n",
    "                \"required\": [\"weight\", \"distance\", \"company\"]\n",
    "            }\n",
    "        }\n",
    "    },\n",
    "    {\n",
    "        \"type\": \"function\",\n",
    "        \"function\": {\n",
    "            \"name\": \"estimate_delivery_time\",\n",
    "            \"description\": \"估算配送时效\",\n",
    "            \"parameters\": {\n",
    "                \"type\": \"object\",\n",
    "                \"properties\": {\n",
    "                    \"from_city\": {\"type\": \"string\", \"description\": \"起始城市\"},\n",
    "                    \"to_city\": {\"type\": \"string\", \"description\": \"目的城市\"},\n",
    "                    \"company\": {\"type\": \"string\", \"description\": \"物流公司\"}\n",
    "                },\n",
    "                \"required\": [\"from_city\", \"to_city\", \"company\"]\n",
    "            }\n",
    "        }\n",
    "    },\n",
    "    {\n",
    "        \"type\": \"function\",\n",
    "        \"function\": {\n",
    "            \"name\": \"track_shipment\",\n",
    "            \"description\": \"查询物流状态\",\n",
    "            \"parameters\": {\n",
    "                \"type\": \"object\",\n",
    "                \"properties\": {\n",
    "                    \"tracking_number\": {\"type\": \"string\", \"description\": \"运单号\"}\n",
    "                },\n",
    "                \"required\": [\"tracking_number\"]\n",
    "            }\n",
    "        }\n",
    "    }\n",
    "]\n",
    "\n",
    "\n",
    "def query_logistics_companies():\n",
    "    return \"支持的物流公司: 顺丰, 圆通, 中通, 韵达, 京东物流, 德邦\"\n",
    "\n",
    "def calculate_shipping_fee(weight, distance, company):\n",
    "    # 物流公司基础运费表\n",
    "    base_fees = {\n",
    "        \"顺丰\": 15, \"圆通\": 8, \"中通\": 8, \n",
    "        \"韵达\": 7, \"京东物流\": 12, \"德邦\": 10\n",
    "    }\n",
    "    base_fee = base_fees.get(company, 10)\n",
    "    weight_fee = weight * 1.5\n",
    "    distance_fee = distance * 0.3\n",
    "    total = base_fee + weight_fee + distance_fee\n",
    "    return f\"{company}快递: 重量{weight}kg, 距离{distance}km, 预估运费{total:.2f}元\"\n",
    "\n",
    "def estimate_delivery_time(from_city, to_city, company):\n",
    "    # 简单的时效估算逻辑\n",
    "    if from_city == to_city:\n",
    "        return \"同城配送，预计1天内送达\"\n",
    "    else:\n",
    "        return \"跨城配送，预计1-3天送达\"\n",
    "\n",
    "def track_shipment(tracking_number):\n",
    "    # 模拟物流状态查询\n",
    "    statuses = [\n",
    "        \"已揽收\", \"运输中\", \"到达目的地分拨中心\", \"派送中\", \"已签收\"\n",
    "    ]\n",
    "    import random\n",
    "    status = random.choice(statuses)\n",
    "    return f\"运单号 {tracking_number} 当前状态: {status}\"\n",
    "\n",
    "\n",
    "# Step 2: 调用模型获取调用意图（物流场景示例）\n",
    "messages = [{\"role\": \"user\", \"content\": \"从北京寄5kg包裹到上海，用顺丰快递要多少钱？\"}]\n",
    "llm_output = call_llm(messages, tools=LOGISTICS_TOOLS)\n",
    "\n",
    "# Step 3: 解析并本地执行函数调用\n",
    "if llm_output.get(\"tool_calls\"):\n",
    "    tool_call = llm_output[\"tool_calls\"][0]\n",
    "    function_name = tool_call[\"function\"][\"name\"]\n",
    "    args = json.loads(tool_call[\"function\"][\"arguments\"])\n",
    "    \n",
    "    if function_name == \"calculate_shipping_fee\":\n",
    "        result = calculate_shipping_fee(args[\"weight\"], args[\"distance\"], args[\"company\"])\n",
    "    elif function_name == \"estimate_delivery_time\":\n",
    "        result = estimate_delivery_time(args[\"from_city\"], args[\"to_city\"], args[\"company\"])\n",
    "    elif function_name == \"query_logistics_companies\":\n",
    "        result = query_logistics_companies()\n",
    "    elif function_name == \"track_shipment\":\n",
    "        result = track_shipment(args[\"tracking_number\"])\n",
    "\n",
    "# Step 4: 将结果回传给模型生成最终回复\n",
    "messages.append({\n",
    "    \"role\": \"tool\", \n",
    "    \"content\": result,\n",
    "    \"tool_call_id\": tool_call[\"id\"]\n",
    "})\n",
    "final_response = call_llm(messages)\n",
    "\n",
    "\n",
    "\n",
    "# 查询物流公司\n",
    "messages = [{\"role\": \"user\", \"content\": \"有哪些物流公司可以选择？\"}]\n",
    "\n",
    "# 查询配送时效  \n",
    "messages = [{\"role\": \"user\", \"content\": \"从深圳到广州要几天能到？\"}]\n",
    "\n",
    "# 查询物流状态\n",
    "messages = [{\"role\": \"user\", \"content\": \"帮我查一下运单号SF1234567890的状态\"}]\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "e157a22e",
   "metadata": {},
   "outputs": [],
   "source": [
    "# 基于 MCP 的实现\n",
    "\n",
    "# Step 0: 初始化 MCP 客户端，动态发现物流工具\n",
    "client = Client()\n",
    "await client.connect(\"mcp://logistics-service.com\")\n",
    "tools = await client.list_tools()  # 自动获取远程物流工具清单\n",
    "\n",
    "\n",
    "\n",
    "# 完整的 MCP 调用\n",
    "# 构建MCP工具提示\n",
    "def build_mcp_tool_prompt(tools):\n",
    "    tool_descs = \"\\n\".join(f\"<tool>{t['name']}</tool>: {t['description']}\" for t in tools)\n",
    "    return f\"\"\"\n",
    "你是一个物流智能助手，可以使用以下工具解决物流相关问题。\n",
    "可用工具列表：\n",
    "{tool_descs}\n",
    "\n",
    "请按如下 XML 格式调用工具：\n",
    "<tool_use>\n",
    "  <name>工具名称</name>\n",
    "  <arguments>{{\"参数1\": \"值1\", \"参数2\": \"值2\"}}</arguments>\n",
    "</tool_use>\n",
    "\n",
    "示例：\n",
    "<tool_use>\n",
    "  <name>calculate_shipping_fee</name>\n",
    "  <arguments>{{\"weight\": 5, \"distance\": 1200, \"company\": \"顺丰\"}}</arguments>\n",
    "</tool_use>\n",
    "\"\"\"\n",
    "\n",
    "# Step 1: 构造 Prompt 并调用模型识别意图\n",
    "system_prompt = build_mcp_tool_prompt(tools)\n",
    "messages = [\n",
    "    {\"role\": \"system\", \"content\": system_prompt},\n",
    "    {\"role\": \"user\", \"content\": \"从北京寄5kg包裹到上海，用顺丰快递要多少钱？\"}\n",
    "]\n",
    "assistant_response = await call_llm(messages)\n",
    "\n",
    "# Step 2: 解析模型输出并远程调用工具\n",
    "tool_use = parse_tool_use(assistant_response)\n",
    "if tool_use:\n",
    "    result = await client.call_tool(\n",
    "        name=tool_use[\"name\"],\n",
    "        arguments=tool_use[\"arguments\"]\n",
    "    )\n",
    "\n",
    "# Step 3: 返回结果供模型生成最终响应\n",
    "messages.append({\n",
    "    \"role\": \"tool\", \n",
    "    \"content\": result,\n",
    "    \"tool_call_id\": tool_use.get(\"id\")\n",
    "})\n",
    "final_response = await call_llm(messages)\n",
    "\n",
    "\n",
    "# 工具解析函数\n",
    "def parse_tool_use(response):\n",
    "    import re\n",
    "    import json\n",
    "    \n",
    "    match = re.search(\n",
    "        r\"<tool_use>\\s*<name>(.*?)</name>\\s*<arguments>(.*?)</arguments>\\s*</tool_use>\", \n",
    "        response, \n",
    "        re.DOTALL\n",
    "    )\n",
    "    if match:\n",
    "        name, args_str = match.groups()\n",
    "        try:\n",
    "            arguments = json.loads(args_str.strip())\n",
    "            return {\"name\": name.strip(), \"arguments\": arguments}\n",
    "        except json.JSONDecodeError:\n",
    "            return None\n",
    "    return None\n",
    "\n",
    "\n",
    "\n"
   ]
  }
 ],
 "metadata": {
  "language_info": {
   "name": "python"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
